<script lang="ts" setup>
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';

import { Page } from '@vben/common-ui';
import { useUserStore } from '@vben/stores';

import {
  Avatar,
  Button,
  Card,
  Input,
  message,
  Select,
  Tooltip,
} from 'ant-design-vue';

import { aiChatSimple } from '#/api/ai/ai';
import { Icon } from '#/components/icon';

// 导入共享组件
// 导入公共的useTheme组合式函数
// 导入聊天特定的组合式函数
import { useChatMessages } from './composables/useChatMessages';
import { useSocketConnection } from './composables/useSocketConnection';

// 状态管理
const loading = ref(false);
const messageInput = ref('');
const selectedModel = ref('qwen-max');
const messagesContainerRef = ref<HTMLElement | null>(null);
const useStream = ref(true);

// 获取用户信息
const userStore = useUserStore();
const userId = userStore.userInfo?.userId;
const userAvatar = userStore.userInfo?.avatar;
const userNickname = userStore.userInfo?.nickname || '用户';

// 可用模型选项
const modelOptions = [
  { label: 'DeepSeek', value: 'deepseek-r1' },
  { label: '通义千问', value: 'qwen-max' },
];

// 模型名称的计算属性
const getModelLabel = computed(() => {
  return (modelValue: string) =>
    modelOptions.find((m) => m.value === modelValue)?.label || modelValue;
});

// 使用组合式函数
const { socketClient, initSocketConnection, isConnected } =
  useSocketConnection(userId);
const {
  messages,
  addUserMessage,
  addAIMessage,
  updateAIMessage,
  clearMessages,
  startTypingAnimation,
  stopTypingAnimation,
} = useChatMessages(selectedModel, userNickname, userAvatar);

// 自动滚动到底部 - 使用原生DOM方法
const scrollToLatestMessage = async () => {
  await nextTick();
  if (messagesContainerRef.value) {
    messagesContainerRef.value.scrollTop =
      messagesContainerRef.value.scrollHeight;
  }
};

// 解析响应数据的辅助函数
const parseResponseData = (data: any): string => {
  // 方式2: 直接是字符串
  if (typeof data === 'string') {
    try {
      // 尝试解析为JSON
      const jsonData = JSON.parse(data);
      return jsonData?.content || jsonData?.message || jsonData?.text || '';
    } catch {
      // 如果不是JSON格式，直接使用字符串
      return data;
    }
  }

  return '';
};

// 使用Socket.IO发送消息并接收流式响应
const sendMessageWithSocketIO = async (
  aiMessageId: string,
  userInput: string,
) => {
  if (!isConnected.value) {
    // 如果没有连接，尝试重新连接
    initSocketConnection();

    if (!isConnected.value) {
      // 如果仍然无法连接，使用普通模式
      message.warning('无法连接到服务器，将使用普通模式');
      useStream.value = false;
      return false;
    }
  }

  try {
    // 启动加载动画
    startTypingAnimation(aiMessageId);

    // 先移除之前的response事件监听器，避免重复订阅
    socketClient.value?.off('response');

    // 处理流式响应
    let isFirstMessage = true;

    // 监听服务端返回的response事件
    socketClient.value?.on('response', (data) => {
      console.error('收到服务端response事件数据:', data);

      // 第一条消息时，清除加载动画
      if (isFirstMessage) {
        stopTypingAnimation();
        updateAIMessage(aiMessageId, '');
        isFirstMessage = false;
      }

      // 尝试解析不同格式的数据
      const content = parseResponseData(data);

      // 如果解析出内容，添加到消息中
      if (content) {
        updateAIMessage(aiMessageId, (prev) => prev + content);
        scrollToLatestMessage();
      }
    });

    // 处理任何错误
    socketClient.value?.once('error', (error) => {
      console.error('Socket.IO错误:', error);
      stopTypingAnimation();
      message.error('接收数据出错，请重试');
    });

    // 发送用户消息到服务器，事件名为模型名称
    console.error(
      `发送消息到服务器，事件名: ${selectedModel.value}，内容: ${userInput}`,
    );

    // 使用纯字符串格式发送用户消息
    socketClient.value?.emit(selectedModel.value, userInput);

    // 监听完成事件，用于清理资源
    socketClient.value?.once('done', () => {
      console.error('服务端处理完成');
    });

    return true;
  } catch (error) {
    console.error('使用Socket.IO发送消息失败:', error);
    stopTypingAnimation();
    message.error('发送消息失败，请重试');
    return false;
  }
};

// 发送消息
const handleSendMessage = async () => {
  if (!messageInput.value.trim()) {
    message.warning('请输入消息内容');
    return;
  }

  // 获取用户输入并清空输入框
  const userInput = messageInput.value;
  messageInput.value = '';

  // 添加用户消息
  addUserMessage(userInput);

  // 滚动到最新消息
  await scrollToLatestMessage();

  // 显示加载状态
  loading.value = true;

  try {
    // 创建AI回复的占位符
    const aiMessageId = addAIMessage('思考中...');
    await scrollToLatestMessage();

    let success = false;

    if (useStream.value) {
      // 尝试使用Socket.IO发送消息
      success = await sendMessageWithSocketIO(aiMessageId, userInput);
    } else {
      // 使用普通请求
      const response = await aiChatSimple(selectedModel.value, userInput);
      stopTypingAnimation();
      updateAIMessage(aiMessageId, response);
      await scrollToLatestMessage();
      success = true;
    }

    if (!success) {
      message.error('获取AI回复失败，请重试');
    }
  } catch (error) {
    console.error('发送消息出错:', error);
    message.error('发送消息失败，请重试');
    stopTypingAnimation();
  } finally {
    loading.value = false;
  }
};

// 监听Enter键发送消息
const handleKeyDown = (e: KeyboardEvent) => {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    handleSendMessage();
  }
};

// 切换模型或响应模式
const handleModeChange = () => {
  // 如果使用流式响应，确保Socket.IO连接已建立
  if (useStream.value && !isConnected.value) {
    initSocketConnection();
  }
};

// 组件挂载时初始化
onMounted(() => {
  // 如果使用流式响应，初始化Socket.IO连接
  if (useStream.value) {
    initSocketConnection();
  }

  // 主题已经在useTheme中自动处理了，不需要额外初始化
});

// 组件卸载时清理资源
onBeforeUnmount(() => {
  // 清除加载动画计时器
  stopTypingAnimation();

  // 断开Socket.IO连接在useSocketConnection中已处理
});
</script>

<template>
  <Page auto-content-height>
    <Card title="AI通用对话" :bordered="false" class="ai-card chat-card">
      <template #extra>
        <div class="control-panel">
          <!-- 模型选择 -->
          <Tooltip title="选择AI模型">
            <Select
              v-model:value="selectedModel"
              style="width: 140px; margin-right: 12px"
              @change="handleModeChange"
            >
              <Select.Option
                v-for="option in modelOptions"
                :key="option.value"
                :value="option.value"
              >
                {{ option.label }}
              </Select.Option>
            </Select>
          </Tooltip>

          <!-- 响应模式开关 -->
          <Tooltip title="流式响应：实时返回结果">
            <Button
              type="link"
              :class="{ 'active-mode': useStream }"
              @click="
                useStream = true;
                handleModeChange();
              "
              style="margin-right: 8px"
            >
              <Icon icon="ant-design:thunderbolt-outlined" />
              流式
            </Button>
          </Tooltip>

          <Tooltip title="普通响应：等待完整结果">
            <Button
              type="link"
              :class="{ 'active-mode': !useStream }"
              @click="
                useStream = false;
                handleModeChange();
              "
              style="margin-right: 12px"
            >
              <Icon icon="ant-design:check-circle-outlined" />
              普通
            </Button>
          </Tooltip>

          <!-- 清空按钮 -->
          <Tooltip title="清空对话记录">
            <Button
              type="primary"
              @click="clearMessages"
              class="animated-button"
            >
              <Icon icon="ant-design:clear-outlined" />
              清空对话
            </Button>
          </Tooltip>
        </div>
      </template>

      <!-- 聊天消息区域 -->
      <div class="chat-container">
        <div class="messages-container" ref="messagesContainerRef">
          <div
            v-for="msg in messages"
            :key="msg.id"
            class="message"
            :class="[msg.isUser ? 'user-message' : 'ai-message']"
          >
            <Avatar
              class="avatar"
              :class="[msg.isUser ? 'user-avatar' : 'ai-avatar']"
              :src="msg.isUser && msg.avatar ? msg.avatar : undefined"
            >
              <template v-if="msg.isUser && !msg.avatar">
                {{ msg.nickname?.[0] || userNickname[0] }}
              </template>
              <template v-else-if="msg.isUser">
                <!-- 使用头像图片，由src属性提供 -->
              </template>
              <template v-else>
                <Icon icon="ant-design:robot-filled" />
              </template>
            </Avatar>
            <div class="message-content">
              <div class="message-header">
                <span class="user-name" v-if="msg.isUser">
                  {{ msg.nickname || userNickname }}
                </span>
                <span class="model-tag" v-if="msg.model">
                  {{ getModelLabel(msg.model) }}
                </span>
                <span class="timestamp">{{
                  new Date(msg.timestamp).toLocaleTimeString()
                }}</span>
              </div>
              <div
                class="message-text"
                v-html="msg.content.replace(/\n/g, '<br>')"
              ></div>
            </div>
          </div>
        </div>

        <!-- 输入区域 -->
        <div class="input-container">
          <Input.TextArea
            v-model:value="messageInput"
            placeholder="请输入您的问题..."
            :rows="3"
            :disabled="loading"
            @keydown="handleKeyDown"
            class="message-input"
          />
          <Button
            type="primary"
            :loading="loading"
            :disabled="!messageInput.trim()"
            @click="handleSendMessage"
            class="send-button animated-button"
          >
            <Icon icon="ant-design:send-outlined" />
            发送
          </Button>
        </div>
      </div>
    </Card>
  </Page>
</template>

<style lang="less" scoped>
// 引入通用样式和主题变量
@import '../styles/common.less';
@import '../styles/theme.less';

// 聊天界面特定样式
.chat-container {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 250px);
  min-height: 500px;
}

.messages-container {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 16px;
  padding: 16px;
  overflow-y: auto;
  background-color: transparent;
  border-radius: 8px;
}

.message {
  display: flex;
  gap: 12px;
  max-width: 85%;
  animation: fadeIn 0.3s ease-in-out;
}

.user-message {
  flex-direction: row-reverse;
  align-self: flex-end;
}

.ai-message {
  align-self: flex-start;
}

.avatar {
  flex-shrink: 0;
  box-shadow: 0 2px 8px rgb(24 144 255 / 30%);
  transition: transform 0.2s ease;

  &:hover {
    transform: scale(1.1);
  }
}

.user-avatar {
  background-color: #722ed1;
  box-shadow: 0 2px 8px rgb(114 46 209 / 30%);
}

.ai-avatar {
  background-color: #1890ff;
}

.message-content {
  padding: 12px 16px;
  word-break: break-word;
  border-radius: 12px;
  box-shadow: 0 2px 6px rgb(0 0 0 / 15%);
  transition: box-shadow 0.3s ease;

  &:hover {
    box-shadow: 0 4px 12px rgb(0 0 0 / 25%);
  }
}

.message-header {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
  font-size: 12px;
  color: #aaa;
}

.user-name {
  padding: 3px 10px;
  font-size: 13px;
  font-weight: bold;
  color: var(--username-color);
  text-shadow: 0 1px 2px rgb(0 0 0 / 80%);
  letter-spacing: 0.5px;
  background-color: var(--username-bg);
  border-radius: 4px;
  box-shadow: 0 1px 3px rgb(0 0 0 / 30%);
}

.model-tag {
  padding: 2px 8px;
  margin-right: auto;
  font-size: 11px;
  font-weight: 500;
  color: var(--model-tag-color);
  background-color: var(--model-tag-bg);
  border: 1px solid var(--model-tag-border);
  border-radius: 4px;
}

.timestamp {
  padding: 1px 6px;
  font-size: 11px;
  color: var(--timestamp-color);
  background-color: var(--timestamp-bg);
  border-radius: 3px;
  opacity: 0.8;
}

.message-text {
  line-height: 1.6;
  letter-spacing: 0.3px;
}

.user-message .message-content {
  color: var(--text-color);
  background-color: var(--user-msg-bg);
  border: 1px solid var(--user-msg-border);
  border-bottom-right-radius: 0;
}

.ai-message .message-content {
  color: var(--text-color);
  background-color: var(--ai-msg-bg);
  border: 1px solid var(--ai-msg-border);
  border-bottom-left-radius: 0;
}

.input-container {
  display: flex;
  gap: 12px;
  padding: 16px;
  margin-top: 16px;
  background-color: var(--input-container-bg);
  border-radius: 8px;
  box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
}

.message-input {
  color: var(--input-text);
  resize: none;
  background-color: var(--input-bg);
  border-color: var(--input-border);
  border-radius: 8px;
  transition: all 0.3s;

  &:hover,
  &:focus {
    border-color: #722ed1;
    box-shadow: 0 0 0 2px rgb(114 46 209 / 20%);
  }
}

.send-button {
  align-self: flex-end;
  height: 40px;
  border-radius: 8px;
}

.control-panel {
  display: flex;
  align-items: center;
}

.active-mode {
  font-weight: bold;
  color: #1890ff;
  text-decoration: underline;
}
</style>
